#pragma once
#include <vector>
#include <string>
#include "Reactor.hpp"
#include "Util.hpp"

#define ONCE_SIZE 128 //一次读取的大小

// 1: 本轮读取全部完成
//-1: 读取出错
// 0: 对端关闭链接
static int RecverCore(int sock, string &inbuffer)
{
    while (true)
    {
        char buffer[ONCE_SIZE];
        ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (s > 0)
        {
            buffer[s] = '\0';
            //读取成功
            inbuffer += buffer;
        }
        else if (s < 0) //读取有误
        {
            if (errno == EINTR)
            {
                // IO信号中断，需要重新读取
                continue;
                ;
            }
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                //数据读取完毕，正常退出
                return 1;
            }
            return -1; //读取出错
        }
        else // s==0
        {
            //对端关闭
            return 0;
        }
    }
}
int Recver(Event *evp)
{
    std::cout << "Recver been called" << std::endl;

    // 1. 真正的读取,将数据读取到inbuffer里
    int result = RecverCore(evp->sock, evp->inbuffer);
    if (result <= 0)
    {
        if (evp->errorer)
        {
            //差错处理
            evp->errorer(evp);
        }
        return -1;
    }
    // 1+2X3+4X5+6X
    //  2. 分包-- 一个或者多个报文 -- 解决粘包问题
    std::vector<std::string> tokens;
    std::string sep = "X";
    SplitSegment(evp->inbuffer, tokens, sep);
    // 3. 反序列化 -- 针对一个报文 -- 提取有效参与计算或者存储的信息
    for (auto &seg : tokens)
    {
        std::string data1, data2;
        if (Deserialize(seg, data1, data2))
        {
            // 4. 业务逻辑 -- 得到结果
            int x = atoi(data1.c_str());
            int y = atoi(data2.c_str());
            int z = x + y;
            // 5. 构建响应 -- 添加到evp->outbuffer
            // 2+3X -> 2+3=5X
            std::string ret = data1;
            ret += "+";
            ret += data2 + "=" + std::to_string(z);
            ret += sep;

            evp->outbuffer += ret; //将数据放到该文件描述符下的输出缓冲区里
        }
    }
    // 6. 尝试直接间接进行发送
    // 一般只要将报文处理完毕，才需要发送
    // 写事件一般基本都是就绪的，但是用户数据不一定是就绪的！
    // 所以对于写事件，按需设置
    if (!(evp->outbuffer).empty())
    {
        //写打开的时候，默认就是就绪的！即便是发送缓冲区已经满了
        // epoll中：只要用户重新设者了OUT事件，EPOLLOUT至少会再触发一次！
        evp->R->EnableRW(evp->sock, true, true);
    }
    return 0;
}
// 1: 全部将数据发送完成
// 0: 数据没有发完，但是不能再发了
//-1: 发送失败
int SenderCore(int sock, std::string& outbuffer)
{
    int total = 0;//本轮累计发送的数据量
    int size = outbuffer.size();
    const char *start = outbuffer.c_str();
    while(true)
    {
        ssize_t curr = send(sock, start + total, size - total, 0);
        if(curr > 0)
        {
            total += curr;
            if(total == size)
            {
                //全部将数据发送完成
                outbuffer.clear();
                return 1;
            }
        }
        else
        {
            if (errno == EINTR)//信号中断
                continue;
            //数据没有发完，但是不能再发了！
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                outbuffer.erase(0, total);
                return 0;
            }

            return -1;
        }
    }
}
int Sender(Event *evp)
{
    std::cout << "Sender been called" << std::endl;

    //先将数据都放到发送缓冲区里
    int result = SenderCore(evp->sock, evp->outbuffer);
    if(result == 1)
    {
        //说明发送成功，可以关闭对该文件描述符的 写事件监听
        evp->R->EnableRW(evp->sock, true, false); //按需设置
    }
    else if (result == 0)
    {
        //可以什么都不做
        evp->R->EnableRW(evp->sock, true, true); //按需设置
    }
    else
    {
        //差错处理
        if (evp->errorer)
        {
            evp->errorer(evp);
        }
    }
}
int Errorer(Event *evp)
{
    std::cout << "Errorer been called" << std::endl;
    evp->R->DeleteEvent(evp);
}